#pragma once

#include <engine.script/Object.hpp>
#include <engine.script/System.hpp>

#include "exports.hpp"
#include "Components.hpp"




namespace Engine
{
	namespace Entity
	{
		class Object;

		class ENGINE_ENTITY_API Component
			: public Script::Object
		{
		public:

			typedef Script::pointer<Component>      ptr; //< pointer type
			typedef unsigned int                    ID;  //< ID, identifying each component implementation
			typedef std::vector<ID>                 IDs;
			typedef boost::unordered_map<ID, ptr>   map; //< Maps an ID to a Component

			Component(bool requiresUpdate = false);
			virtual ~Component();



			/**
			 * This function is called whenever this component is attached to an entity.
			 * Stores a pointer to the entity.
			 *
			 * @param entity       the entity this component is attached to
			 * @param components   all components (of the given entity) this component requires to function properly
			 */
			virtual void attached(Entity::Object* entity, const map& components);

			/**
			 * This function is called whenever this component is detached from an entity.
			 * @throws invalid_value_exception in case the given entity is not the one this component is attached to
			 */
			virtual void detached(Entity::Object* entity);



			/**
			 * @returns a pointer to the entity this component is attached to
			 * @returns nullptr in case this component is not attached to an entity
			 */
			Entity::Object* entity() const;

			/**
			 * Tests if this component is attached to an entity or not.
			 */
			bool isAttached() const;



			/**
			 * Updates this component.
			 * Does not need to be implemented.
			 */
			virtual void update();

			/**
			 * @returns a number that identifies the type of a component.
			 */
			virtual ID id() const = 0;

			/**
			 * Tests if this component requires a call to update or not.
			 */
			virtual bool requiresUpdate() const;



			/**
			 * @returns a list of required components
			 */
			virtual std::vector<ID> requiredComponents() const;



			static void registerType(Script::System::ptr engine);

		private:

			bool              m_requiresUpdate;
			Entity::Object*   m_entity;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
